/* 
 * File:   Calendar.c
 * Author: Muqtafi Akhmad
 */

#include "Calendar.h"
#include "../ADTCSString/CSString.h"

/**
 * Returns an empty Calendar
 * @return calendar
 */
Calendar MakeCalendar() {
    Calendar c;
    CreateEventList(&(c.events));
    return c;
}

/**
 * Returns list of events in the calendar
 * @param calendar the calendar
 * @return list of events
 */
EventList GetEvents(Calendar calendar) {
    return calendar.events;
}

/**
 * Set list of events
 * @param calendar the calendar
 * @param events the new list of event
 */
void SetEvents(Calendar *calendar, EventList events) {
    calendar->events = events;
}

/**
 * View an event given the entry number
 * @param calendar the calendar
 * @param args entry number
 */
void View(Calendar *calendar, char** args) {
    if (args[1]) {
        long entryNo = atol(args[1]);
        EventAddr addr = SearchEventByEntryNo(GetEvents(*calendar), entryNo);
        if (addr == NULL) {
            // event not found
            printf("Event with entry number %ld not found \n", entryNo);
        } else {
            // event found, print
            PrintEvent(Info(addr));
        }
    }
}

/**
 * Add a new event to the calendar
 * @param calendar the calendar
 * @param args the new event entry number
 */
void Add(Calendar *calendar, char** args) {
    if (args[1]) {
        long entryNo = atol(args[1]);
        EventAddr addr = SearchEventByEntryNo(GetEvents(*calendar), entryNo);
        if (addr != NULL) {
            printf("Event with entry number %ld already exists \n", entryNo);
        } else {
            printf("Please fill in the event details \n");
            // read event description
            printf("Event description : \n\t");
            char description[EVENT_DESCRIPTION_MAX_LENGTH];
            gets(description);

            // read event position
            printf("Event position (lat, long) : \n\t");
            char buff[100];
            CSString pointBuff[100];
            gets(buff);
            int pointCount = Split(Trim(buff), pointBuff, ",");
            Point position = MakePoint(0, 0);
            if (pointCount > 1) {
                position = MakePoint(atof(Trim(pointBuff[0])), atof(Trim(pointBuff[1])));
            }

            // read date time
            printf("Event date and time (YYYY-MM-DD@hour:min:sec) : \n\t");
            gets(buff);
            DateTime dateTime = ParseDateTime(buff);

            // read participants
            printf("Number of participants : \n\t");
            int participantCount, iter;
            char** participants;
            scanf("%d", &participantCount);
            gets(buff);
            participants = (char**) malloc(participantCount * sizeof (char*));
            for (iter = 0; iter < participantCount; iter++) {
                printf("        Participant #%d : ", iter + 1);
                participants[iter] = (char*) malloc(PARTICIPANT_NAME_MAX_LENGTH * sizeof (char));
                gets(participants[iter]);
            }
            // insert event to event list
            InsertEvent(&(calendar->events), MakeEvent(entryNo, dateTime, position, description, participants, participantCount));

            printf("Success inserting new event with entry number %ld \n", entryNo);
        }
    }
}

/**
 * Delete an event from list of events in calendar
 * @param calendar the calendar
 * @param args the entry number of deleted event
 */
void Delete(Calendar *calendar, char** args) {
    if (args[1]) {
        long entryNo = atol(args[1]);
        EventAddr addr = SearchEventByEntryNo(GetEvents(*calendar), entryNo);
        if (addr == NULL) {
            printf("Event with entry number %ld not found  \n", entryNo);
        } else {
            // event exists, delete event
            DeleteEvent(&(calendar->events), entryNo);
            printf("Success deleting new event with entry number %ld \n", entryNo);
        }
    }
}

/**
 * Load a calendar file and read the events
 * @param calendar the calendar read
 * @param args file name
 */
void LoadCalendar(Calendar* calendar, char** args) {
    if (args[1]) {
        CSString string = readContent(args[1]);
        /*Events*/
        CSString currEvent [100];
        /* Data for each event */
        CSString eventData[100];
        CSString pointData[100];
        Split(string, currEvent, "#");
        /* Check number of event */
        if (currEvent[0]) {
            int eventCount;
            eventCount = atoi(Trim(currEvent[0]));
            CreateEventList(&(calendar->events));
            int i;
            for (i = 0; i < eventCount; i++) {
                CSString eventDataTrimmed = Trim(currEvent[i + 1]);
                int dataLength = Split(eventDataTrimmed, eventData, "\n");
                Event _event;
                if (dataLength >= 4) {
                    //set number
                    SetEntryNo(&_event, atol(Trim(eventData[0])));
                    //set description
                    SetDescription(&_event, Trim(eventData[1]));
                    //set position
                    int pointLength = Split(Trim(eventData[2]), pointData, ",");
                    if (pointLength >= 2) {
                        CSString latitude = Trim(pointData[0]);
                        CSString longitude = Trim(pointData[1]);
                        Point position = MakePoint(atof(latitude), atof(longitude));
                        SetPosition(&_event, position);
                    } else {
                        printf("Point has Wrong Format \n");
                    }
                    //set date time
                    SetDateTime(&_event, ParseDateTime(Trim(eventData[3])));
                    //set participants
                    char* participants[PARTICIPANT_MAX_COUNT];
                    int participantCount = Split(Trim(eventData[4]), participants, ",");
                    int participantCounter;
                    for (participantCounter = 0; participantCounter < participantCount; participantCounter++) {
                        participants[participantCounter] = Trim(participants[participantCounter]);
                    }
                    SetParticipants(&_event, participants, participantCount);
                    InsertEvent(&(calendar->events), _event);
                    DeallocParticipants(&_event);
                } else {
                    printf("Wrong File Format Parameter Count\n");
                }
            }
        } else {
            printf("Wrong File Format : No Event Number\n");
        }
    } else {
        printf("Please specify file name\n");
        printf("Usage Load <filename>");
    }
}

/**
 * Save event in list to a file
 * @param calendar the calendar
 * @param args file name to save events
 */
void SaveCalendar(Calendar* calendar, char** args) {
    if (args[1]) {
        if (EventListEmpty(calendar->events)) {
            // create empty file
            SaveFile("0\n", args[1]);
        } else {
            // starts writing file
            int eventCount = NbElement(calendar->events);
            char* temp = (char*) malloc(40 * sizeof (char));
            sprintf(temp, "%d\n", eventCount);
            // create file
            SaveFile(temp, args[1]);
            free(temp);
            // writing events
            EventAddr ptr = First(calendar->events);
            while (ptr != NULL) {
                AppendFile(EventToString(Info(ptr)), args[1]);
                ptr = Next(ptr);
            }
        }
    }
}

/**
 * Set calendar to empty calendar, dealloc previous evente
 * @param calendar the calendar
 * @param args empty arguments
 */
void CreateCalendar(Calendar *calendar, char** args) {
    if (!EventListEmpty(calendar->events)) {
        // dealloc events
        Dealokasi(&(calendar->events));
    }
}

/**
 * Prints n first events
 * @param calendar the calendar
 * @param args empty arguments
 */
void PrintFirst(Calendar *calendar, char** args) {
    int count = atoi(args[1]);
    if (count >= NbElement(GetEvents(*calendar))) {
        PrintInfo(GetEvents(*calendar));
    } else {
        EventAddr addr = First(GetEvents(*calendar));
        int iter = 0;
        while (addr != NULL && iter < count) {
            PrintEvent(Info(addr));
            addr = Next(addr);
            iter++;
        }
    }
}

/**
 * Prints n last events
 * @param calendar the calendar
 * @param args empty arguments
 */
void PrintLast(Calendar *calendar, char** args) {
    int count = atoi(args[1]);
    if (count >= NbElement(GetEvents(*calendar))) {
        PrintInfo(GetEvents(*calendar));
    } else {
        EventAddr addr = GetLastNAddress(GetEvents(*calendar), count);
        while (addr != NULL) {
            PrintEvent(Info(addr));
            addr = Next(addr);
        }
    }
}

/**
 * Show events in a given date
 * @param calendar the calendar
 * @param args date
 */
void ShowDetail(Calendar* calendar, char**args) {
    if (args[1]) {
        long entryNoBuff[100];
        char dateTimeBuff[100];
        int j;
        for (j = 0; j < 100; j++) {
            dateTimeBuff[j] = '\0';
        }
        strcpy(dateTimeBuff, args[1]);
        strcat(dateTimeBuff, "@00:00:00");
        int count = GetEventCountInDay(calendar->events, ParseDateTime(dateTimeBuff), entryNoBuff, 100), iter;
        if (count > 0) {
            printf("Found %d event(s) : \n", count);
            for (iter = 0; iter < count; iter++) {
                printf("    Event no #%ld \n", entryNoBuff[iter]);
            }
        } else {
            printf("Can't find event\n");
        }
    }
}

/**
 * Main Program Runner
 * @param calendar Current Calendar
 * @param args Arguments
 */
void RunInstructions(Calendar *calendar, char** args) {
    boolean programRunning = true;
    do {
        char commandBuff[1024];
        printf("\n>>");
        gets(commandBuff);
        Split(commandBuff, args, " ");
        if (strcmp(args[0], "Quit") && isCommandExist(args[0])) {
            printf("(!)Execute command\n");
            Execute(args[0], calendar, args);
            printf("(!)Execute success\n");
        } else if (!strcmp(args[0], "Quit")) {
            printf("(!)Quit program\n");
            programRunning = false;
        } else {
            printf("(!)Unknown command %s \n", args[0]);
            printf("*** CSCalendar Help ***\n");
            printf("Available commands : \n");
            printf("1. Create \n");
            printf("2. Load <filename> \n");
            printf("3. View <entry#> \n");
            printf("4. Last <number of event> \n");
            printf("5. First <number of event> \n");
            printf("5. ShowCalendar <YYYY> <MM> \n");
            printf("6. ShowDetail <YYYY-MM-DD> \n");
            printf("7. Add <entry#>\n");
            printf("8. Delete <entry#>\n");
            printf("9. Save <filename>\n");
            printf("10. Quit \n");
        }
    } while (programRunning);
}
